package com.christina.engine.observer.impl;

import com.christina.engine.observer.ProcessingEvent;
import com.christina.engine.observer.ProcessingEventListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.time.format.DateTimeFormatter;
import java.util.EnumSet;
import java.util.Map;

/**
 * 审计日志监听器
 * 负责记录系统的审计日志
 * 
 * @author Christina
 */
@Slf4j
@Component
public class AuditLogListener implements ProcessingEventListener {
    
    private static final String LISTENER_NAME = "AuditLogListener";
    private static final DateTimeFormatter TIMESTAMP_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
    
    // 需要审计的事件类型
    private static final EnumSet<ProcessingEvent.EventType> AUDITABLE_EVENTS = EnumSet.of(
            ProcessingEvent.EventType.REQUEST_RECEIVED,
            ProcessingEvent.EventType.REQUEST_COMPLETED,
            ProcessingEvent.EventType.REQUEST_FAILED,
            ProcessingEvent.EventType.SERVICE_EXECUTION_STARTED,
            ProcessingEvent.EventType.SERVICE_EXECUTION_COMPLETED,
            ProcessingEvent.EventType.SERVICE_EXECUTION_FAILED,
            ProcessingEvent.EventType.USER_LOGIN,
            ProcessingEvent.EventType.USER_LOGOUT,
            ProcessingEvent.EventType.USER_ACTION,
            ProcessingEvent.EventType.ERROR_OCCURRED,
            ProcessingEvent.EventType.SYSTEM_STARTUP,
            ProcessingEvent.EventType.SYSTEM_SHUTDOWN
    );
    
    @Override
    public void onEvent(ProcessingEvent event) {
        try {
            String auditLog = createAuditLog(event);
            
            // 根据事件类型和优先级选择不同的日志级别
            if (event.isCritical()) {
                log.error("[AUDIT-CRITICAL] {}", auditLog);
            } else if (event.isHighPriority()) {
                log.warn("[AUDIT-HIGH] {}", auditLog);
            } else {
                log.info("[AUDIT] {}", auditLog);
            }
            
            // 对于关键事件，可以考虑写入专门的审计日志文件或数据库
            if (isSecurityRelevant(event)) {
                writeSecurityAuditLog(auditLog);
            }
            
        } catch (Exception e) {
            log.error("Error creating audit log for event: {}", event.getEventId(), e);
        }
    }
    
    /**
     * 创建审计日志
     */
    private String createAuditLog(ProcessingEvent event) {
        StringBuilder logBuilder = new StringBuilder();
        
        // 基本信息
        logBuilder.append("EventId=").append(event.getEventId())
                  .append(" | Type=").append(event.getEventType())
                  .append(" | Source=").append(event.getSource())
                  .append(" | Timestamp=").append(event.getTimestamp().format(TIMESTAMP_FORMAT));
        
        // 会话信息
        if (event.getSessionId() != null) {
            logBuilder.append(" | SessionId=").append(event.getSessionId());
        }
        
        // 用户信息
        if (event.getUserId() != null) {
            logBuilder.append(" | UserId=").append(event.getUserId());
        }
        
        // 优先级
        if (event.getPriority() != null) {
            logBuilder.append(" | Priority=").append(event.getPriority());
        }
        
        // 事件数据
        if (event.getEventData() != null && !event.getEventData().isEmpty()) {
            logBuilder.append(" | Data=").append(formatEventData(event.getEventData()));
        }
        
        // 标签
        if (event.getTags() != null && !event.getTags().isEmpty()) {
            logBuilder.append(" | Tags=").append(String.join(",", event.getTags()));
        }
        
        return logBuilder.toString();
    }
    
    /**
     * 格式化事件数据
     */
    private String formatEventData(Map<String, Object> eventData) {
        StringBuilder dataBuilder = new StringBuilder("{");
        
        boolean first = true;
        for (Map.Entry<String, Object> entry : eventData.entrySet()) {
            if (!first) {
                dataBuilder.append(", ");
            }
            
            String key = entry.getKey();
            Object value = entry.getValue();
            
            // 敏感信息脱敏
            if (isSensitiveField(key)) {
                value = maskSensitiveValue(value);
            }
            
            dataBuilder.append(key).append("=").append(value);
            first = false;
        }
        
        dataBuilder.append("}");
        return dataBuilder.toString();
    }
    
    /**
     * 检查是否为敏感字段
     */
    private boolean isSensitiveField(String fieldName) {
        String lowerFieldName = fieldName.toLowerCase();
        return lowerFieldName.contains("password") ||
               lowerFieldName.contains("token") ||
               lowerFieldName.contains("secret") ||
               lowerFieldName.contains("key") ||
               lowerFieldName.contains("credential");
    }
    
    /**
     * 脱敏敏感值
     */
    private String maskSensitiveValue(Object value) {
        if (value == null) {
            return "null";
        }
        
        String stringValue = value.toString();
        if (stringValue.length() <= 4) {
            return "****";
        }
        
        return stringValue.substring(0, 2) + "****" + stringValue.substring(stringValue.length() - 2);
    }
    
    /**
     * 检查是否为安全相关事件
     */
    private boolean isSecurityRelevant(ProcessingEvent event) {
        return event.getEventType() == ProcessingEvent.EventType.USER_LOGIN ||
               event.getEventType() == ProcessingEvent.EventType.USER_LOGOUT ||
               event.getEventType() == ProcessingEvent.EventType.ERROR_OCCURRED ||
               (event.getEventData() != null && 
                (event.getEventData().containsKey("authentication") ||
                 event.getEventData().containsKey("authorization")));
    }
    
    /**
     * 写入安全审计日志
     */
    private void writeSecurityAuditLog(String auditLog) {
        // 这里可以实现写入专门的安全审计日志文件或数据库
        // 为了简化，这里只是使用特殊的日志标记
        log.warn("[SECURITY-AUDIT] {}", auditLog);
        
        // 在实际实现中，可能需要：
        // 1. 写入专门的审计数据库
        // 2. 发送到安全信息和事件管理(SIEM)系统
        // 3. 触发安全告警
    }
    
    @Override
    public String getListenerName() {
        return LISTENER_NAME;
    }
    
    @Override
    public int getPriority() {
        return 20; // 高优先级，确保审计日志及时记录
    }
    
    @Override
    public boolean supportsEventType(ProcessingEvent.EventType eventType) {
        return AUDITABLE_EVENTS.contains(eventType);
    }
    
    @Override
    public boolean isAsync() {
        return false; // 同步处理，确保审计日志的及时性和完整性
    }
    
    @Override
    public ListenerType getListenerType() {
        return ListenerType.AUDIT;
    }
    
    @Override
    public void onError(ProcessingEvent event, Exception exception) {
        // 审计日志记录失败是严重问题，需要特别处理
        log.error("[AUDIT-ERROR] Failed to create audit log for event {} ({}): {}", 
                event.getEventId(), event.getEventType(), exception.getMessage());
        
        // 可以考虑：
        // 1. 发送告警通知
        // 2. 写入备用日志系统
        // 3. 触发系统健康检查
    }
}